/* Copyright (c) 2021 OceanBase and/or its affiliates. All rights reserved.
miniob is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
         http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details. */

#include "common/type/date_type.h"
#include "common/log/log.h"
#include "common/value.h"
#include "common/lang/string.h"
#include "common/type/date_util.h"
#include <cstdio>
#include <cstring>
#include <cmath>


using namespace common;

// -----------------------------------------------------------------------------
// 内部辅助函数实现（私有方法，封装日期解析、格式化、合法性校验逻辑）
// -----------------------------------------------------------------------------

/**
 * @brief 校验日期天数是否在合法范围（1970-01-01 ~ 2038-02-07）
 * @param[in] date_days 日期对应的基准天数（1970-01-01 为 0）
 * @return bool 合法返回true，非法返回false
 */
bool DateType::is_valid_date(int32_t date_days) const {
  return (date_days >= MIN_DATE_DAYS) && (date_days <= MAX_DATE_DAYS);
}

/**
 * @brief 辅助函数：判断年份是否为闰年
 * @param[in] year 待判断的年份（如2024）
 * @return bool 闰年返回true，平年返回false
 */
static bool is_leap_year(int year) {
  // 闰年规则：能被4整除且不能被100整除，或能被400整除
  return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}

/**
 * @brief 辅助函数：获取指定年月的天数（考虑闰年）
 * @param[in] year 年份
 * @param[in] month 月份（1-12）
 * @return int 该月的天数（如2月平年28天、闰年29天）
 */
static int get_days_in_month(int year, int month) {
  // 平年各月天数数组（索引0对应1月，索引1对应2月...）
  static const int DAYS_PER_MONTH[] = {31,28,31,30,31,30,31,31,30,31,30,31};
  if (month < 1 || month > 12) {
    return 0; // 非法月份返回0
  }
  // 2月特殊处理：闰年29天
  if (month == 2 && is_leap_year(year)) {
    return 29;
  }
  return DAYS_PER_MONTH[month - 1];
}

/**
 * @brief 将YYYY-MM-DD格式字符串解析为基准天数
 * @param[in] date_str 输入字符串（如"2025-10-01"）
 * @param[out] date_days 解析后的基准天数（成功时赋值）
 * @return bool 解析成功返回true，失败（格式错误/日期非法）返回false
 */
bool DateType::parse_date_str(const std::string &date_str, int32_t &date_days) const {
  // 1. 校验字符串长度：YYYY-MM-DD 固定10个字符（如2025-10-01）
  if (date_str.size() != 10) {
    LOG_TRACE("Invalid date string length: %zu (expected 10)", date_str.size());
    return false;
  }

  // 2. 校验分隔符位置（第4位和第7位必须是'-'）
  if (date_str[4] != '-' || date_str[7] != '-') {
    LOG_TRACE("Invalid date separator: %s (expected YYYY-MM-DD)", date_str.c_str());
    return false;
  }

  // 3. 解析年、月、日（sscanf返回成功解析的参数个数，需等于3）
  int year, month, day;
  if (sscanf(date_str.c_str(), "%4d-%2d-%2d", &year, &month, &day) != 3) {
    LOG_TRACE("Failed to parse date components: %s", date_str.c_str());
    return false;
  }

  // 4. 基础合法性校验（年份、月份、日期范围）
  if (year < 1970 || year > 2038) {
    LOG_TRACE("Year out of range: %d (1970-2038 allowed)", year);
    return false;
  }
  if (month < 1 || month > 12) {
    LOG_TRACE("Invalid month: %d (1-12 allowed)", month);
    return false;
  }
  if (day < 1 || day > get_days_in_month(year, month)) {
    LOG_TRACE("Invalid day: %d (max %d for %d-%02d)", 
              day, get_days_in_month(year, month), year, month);
    return false;
  }

  // 5. 计算date值
  date_days = year * 10000 + month * 100 + day;

  //由于date类型直接存储为形如20251014这样的量所以不需要获取总天数的计算
  // // 5. 计算从1970-01-01到目标日期的总天数
  // date_days = 0;
  // // 5.1 累加完整年份的天数（1970到目标年份的前一年）
  // for (int y = 1970; y < year; ++y) {
  //   date_days += is_leap_year(y) ? 366 : 365;
  // }
  // // 5.2 累加目标年份中，目标月份前的所有月份天数
  // for (int m = 1; m < month; ++m) {
  //   date_days += get_days_in_month(year, m);
  // }
  // // 5.3 累加目标月份的天数（目标日期-1，因为1号对应0天偏移）
  // date_days += (day - 1);

  // 6. 最终校验date值是否在合法范围（双重保险）
  if (!is_valid_date(date_days)) {
    LOG_TRACE("Parsed date days out of range: %d", date_days);
    return false;
  }
  return true;
}

/**
 * @brief 将date值格式化为YYYY-MM-DD字符串
 * @param[in] date_days 输入的date值如20251014
 * @param[out] date_str 格式化后的字符串（成功时赋值）
 * @return bool 格式化成功返回true，失败（天数非法）返回false
 */
bool DateType::format_date_days(int32_t date_days, std::string &date_str) const {
  // 1. 先校验天数合法性
  if (!is_valid_date(date_days)) {
    LOG_TRACE("Invalid date days: %d (range 0-%d)", date_days, MAX_DATE_DAYS);
    date_str.clear();
    return false;
  }

  //设置date具体值
  int year = date_days / 10000;
  int month = (date_days % 10000) / 100;
  int day = date_days % 100;

  // // 2.1 计算年份：逐年减去该年天数，直到剩余天数小于当年天数
  // while (true) {
  //   int year_days = is_leap_year(year) ? 366 : 365;
  //   if (remaining_days < year_days) {
  //     break;
  //   }
  //   remaining_days -= year_days;
  //   year++;
  // }

  // // 2.2 计算月份：逐月减去该月天数，直到剩余天数小于当月天数
  // while (true) {
  //   int month_days = get_days_in_month(year, month);
  //   if (remaining_days < month_days) {
  //     break;
  //   }
  //   remaining_days -= month_days;
  //   month++;
  // }

  // // 2.3 计算天数：剩余天数+1（因为0对应1号）
  // day += remaining_days;

  // 合法性校验
  if (year < 1 || year > 9999 ||  // 年份限制在 1~9999（4位）
      month < 1 || month > 12 ||   // 月份限制在 1~12
      day < 1 || day > 31) {       // 日期限制在 1~31（实际应更严格，可调用 get_days_in_month 校验）
    return false;
  }

  // 3. 格式化字符串（确保两位数月份/日期，如2025-02-01而非2025-2-1）
  char buf[20] = {0}; // YYYY-MM-DD 共10字符，加终止符共11字节,但是未来兼容异常情况扩容为20字节
  snprintf(buf, sizeof(buf), "%04d-%02d-%02d", year, month, day);
  date_str = buf;

  return true;
}

// -----------------------------------------------------------------------------
// 核心接口实现（继承自DataType的纯虚函数）
// -----------------------------------------------------------------------------

/**
 * @brief 比较两个DATE类型的Value对象
 * @param[in] left 左值（必须为DATE类型）
 * @param[in] right 右值（必须为DATE类型）
 * @return int 比较结果：-1(left<right)、0(相等)、1(left>right)；类型不匹配返回INT32_MAX
 */
int DateType::compare(const Value &left, const Value &right) const {
  // 1. 校验输入类型是否为DATE
  if (left.attr_type() != AttrType::DATES || right.attr_type() != AttrType::DATES) {
    LOG_WARN("Date compare failed: type mismatch (left=%d, right=%d)", 
             left.attr_type(), right.attr_type());
    return INT32_MAX;
  }

  // 2. 获取两个日期的date类型的值如20251014（直接从Value的union中读取int_value）
  int32_t left_days = left.get_date_days();
  int32_t right_days = right.get_date_days();

  // 3. 整数比较（值越大，日期越晚）
  if (left_days < right_days) {
    return -1;
  } else if (left_days > right_days) {
    return 1;
  } else {
    return 0;
  }
}

/**
 * @brief 比较两个Column中指定索引的DATE类型数据
 * @param[in] left 左列（必须为DATE类型）
 * @param[in] right 右列（必须为DATE类型）
 * @param[in] left_idx 左列中数据的索引
 * @param[in] right_idx 右列中数据的索引
 * @return int 比较结果：-1(left<right)、0(相等)、1(left>right)；类型不匹配返回INT32_MAX
 */
int DateType::compare(const Column &left, const Column &right, int left_idx, int right_idx) const {
  // 1. 校验列类型是否为DATE
  if (left.attr_type() != AttrType::DATES || right.attr_type() != AttrType::DATES) {
    LOG_WARN("Column date compare failed: type mismatch (left=%d, right=%d)", 
             left.attr_type(), right.attr_type());
    return INT32_MAX;
  }

  // 2. 校验索引合法性（避免数组越界）
  if (left_idx < 0 || left_idx >= left.count() || right_idx < 0 || right_idx >= right.count()) {
    LOG_WARN("Column date compare failed: invalid index (left_idx=%d, right_idx=%d)", 
             left_idx, right_idx);
    return INT32_MAX;
  }

  // 3. 从列数据中读取指定索引的DATE天数（Column数据存储为int32_t数组）
  int32_t *left_data = reinterpret_cast<int32_t *>(left.data());
  int32_t *right_data = reinterpret_cast<int32_t *>(right.data());
  int32_t left_days = left_data[left_idx];
  int32_t right_days = right_data[right_idx];

  // 4. 整数比较
  if (left_days < right_days) {
    return -1;
  } else if (left_days > right_days) {
    return 1;
  } else {
    return 0;
  }
}

/**
 * @brief 日期加法：DATE + INT（整数表示天数）
 * @param[in] left 左值（DATE类型，基础日期）
 * @param[in] right 右值（INT类型，要添加的天数）
 * @param[out] result 运算结果（需提前设置为DATE类型）
 * @return RC 操作结果：SUCCESS(成功)、SCHEMA_FIELD_TYPE_MISMATCH(类型不匹配)、INVALID_DATE(结果非法)
 */
RC DateType::add(const Value &left, const Value &right, Value &result) const {
  // 1. 校验输入类型：left=DATES，right=INT，result=DATES
  if (left.attr_type() != AttrType::DATES) {
    LOG_WARN("Date add failed: left is not DATE (type=%d)", left.attr_type());
    return RC::SCHEMA_FIELD_TYPE_MISMATCH;
  }
  if (right.attr_type() != AttrType::INTS) {
    LOG_WARN("Date add failed: right is not INT (type=%d)", right.attr_type());
    return RC::SCHEMA_FIELD_TYPE_MISMATCH;
  }
  if (result.attr_type() != AttrType::DATES) {
    LOG_WARN("Date add failed: result is not DATE (type=%d)", result.attr_type());
    return RC::SCHEMA_FIELD_TYPE_MISMATCH;
  }

  // 2. 计算结果天数：基础天数 + 待加天数
  int32_t base_days = left.get_date_days();
  int add_days = right.get_int();
  int32_t result_days = DateUtil::add_days(base_days, add_days);

  // 3. 校验结果天数合法性
  if (!is_valid_date(result_days)) {
    LOG_WARN("Date add result out of range: %d + %d = %d (range 0-%d)", 
             base_days, add_days, result_days, MAX_DATE_DAYS);
    return RC::INVALID_DATE;
  }

  // 4. 设置结果值
  result.set_date(result_days);
  return RC::SUCCESS;
}

/**
 * @brief 日期减法：支持两种场景
 *        1. DATE - INT = DATE（减去指定天数）
 *        2. DATE - DATE = INT（计算两个日期的天数差）
 * @param[in] left 左值（DATE类型）
 * @param[in] right 右值（INT或DATE类型）
 * @param[out] result 运算结果（需提前设置类型：DATE或INT）
 * @return RC 操作结果：SUCCESS(成功)、SCHEMA_FIELD_TYPE_MISMATCH(类型不匹配)、INVALID_DATE(结果非法)
 */
RC DateType::subtract(const Value &left, const Value &right, Value &result) const {
  // 1. 校验左值类型（必须为DATE）
  if (left.attr_type() != AttrType::DATES) {
    LOG_WARN("Date subtract failed: left is not DATE (type=%d)", left.attr_type());
    return RC::SCHEMA_FIELD_TYPE_MISMATCH;
  }

  // 2. 场景1：DATE - INT = DATE（减去天数）
  if (right.attr_type() == AttrType::INTS) {
    // 2.1 校验结果类型（必须为DATE）
    if (result.attr_type() != AttrType::DATES) {
      LOG_WARN("Date subtract failed: result is not DATE (type=%d)", result.attr_type());
      return RC::SCHEMA_FIELD_TYPE_MISMATCH;
    }

    // 2.2 计算结果天数：基础天数 - 待减天数
    int32_t base_days = left.get_date_days();
    int sub_days = right.get_int();
    //减法就是加法的逆运算
    int32_t result_days = DateUtil::add_days(base_days,-sub_days);

    // 2.3 校验结果合法性
    if (!is_valid_date(result_days)) {
      LOG_WARN("Date subtract result out of range: %d - %d = %d (range 0-%d)", 
               base_days, sub_days, result_days, MAX_DATE_DAYS);
      return RC::INVALID_DATE;
    }

    // 2.4 设置结果值
    result.set_date(result_days);
    return RC::SUCCESS;
  }

  // 3. 场景2：DATE - DATE = INT（计算天数差）
  else if (right.attr_type() == AttrType::DATES) {
    // 3.1 校验结果类型（必须为INT）
    if (result.attr_type() != AttrType::INTS) {
      LOG_WARN("Date subtract failed: result is not INT (type=%d)", result.attr_type());
      return RC::SCHEMA_FIELD_TYPE_MISMATCH;
    }

    // 3.2 计算天数差
    int32_t left_days = left.get_date_days();
    int32_t right_days = right.get_date_days();
    int day_diff = DateUtil::get_date_difference(left_days, right_days);

    // 3.3 设置结果值（INT类型）
    result.set_int(day_diff);
    return RC::SUCCESS;
  }

  // 4. 不支持的右值类型
  else {
    LOG_WARN("Date subtract failed: right type not supported (type=%d)", right.attr_type());
    return RC::SCHEMA_FIELD_TYPE_MISMATCH;
  }
}

/**
 * @brief 日期乘法：DATE类型无实际业务意义，直接返回未实现
 * @param[in] left 左值（未使用）
 * @param[in] right 右值（未使用）
 * @param[out] result 结果（未使用）
 * @return RC 固定返回UNIMPL（未实现）
 */
RC DateType::multiply(const Value &left, const Value &right, Value &result) const {
  LOG_WARN("Date multiply not supported");
  return RC::UNIMPL;
}

/**
 * @brief 日期取反：DATE类型无实际意义（负数天数对应1970年前，非法），返回未实现
 * @param[in] val 输入值（未使用）
 * @param[out] result 结果（未使用）
 * @return RC 固定返回UNIMPL（未实现）
 */
RC DateType::negative(const Value &val, Value &result) const {
  LOG_WARN("Date negative not supported");
  return RC::UNIMPL;
}

/**
 * @brief 类型转换：将DATE类型转换为目标类型（支持CHAR/INT，其他类型不支持）
 * @param[in] val 源值（DATE类型）
 * @param[in] type 目标类型（AttrType::CHARS 或 AttrType::INTS）
 * @param[out] result 转换后的结果（需提前初始化）
 * @return RC 操作结果：SUCCESS(成功)、SCHEMA_FIELD_TYPE_MISMATCH(目标类型不支持)
 */
RC DateType::cast_to(const Value &val, AttrType type, Value &result) const {
  // 1. 校验源值类型（必须为DATE）
  if (val.attr_type() != AttrType::DATES) {
    LOG_WARN("Date cast failed: source is not DATE (type=%d)", val.attr_type());
    return RC::SCHEMA_FIELD_TYPE_MISMATCH;
  }

  // 2. 转换为CHAR类型（DATE → 字符串，格式YYYY-MM-DD）
  if (type == AttrType::CHARS) {
    std::string date_str = val.get_date_string();
    // 设置结果为字符串（长度10，无需动态内存释放，由Value内部管理）
    result.set_string(date_str.c_str(), date_str.size());
    return RC::SUCCESS;
  }

  // 3. 转换为INT类型（DATE → 基准天数）
  else if (type == AttrType::INTS) {
    int32_t date_days = DateUtil::date_to_total_days(val.get_date_days());
    result.set_int(date_days);
    return RC::SUCCESS;
  }

  // 4. 不支持的目标类型
  else {
    LOG_WARN("Date cast to %d not supported", type);
    return RC::SCHEMA_FIELD_TYPE_MISMATCH;
  }
}

/**
 * @brief 计算类型转换成本（用于查询优化器选择最优转换路径）
 * @param[in] type 目标转换类型
 * @return int 转换成本：0(同类型)、1(低成本)、INT32_MAX(不支持)
 */
int DateType::cast_cost(const AttrType type) {
  if (type == AttrType::DATES) {
    return 0; // 同类型转换，无成本
  } else if (type == AttrType::CHARS || type == AttrType::INTS) {
    return 1; // 低成本转换（字符串/整数互转，仅需简单计算）
  } else {
    return INT32_MAX; // 不支持的转换，成本无穷大
  }
}

/**
 * @brief 从字符串解析日期，设置到Value对象
 * @param[out] val 要设置的Value（结果类型为DATE）
 * @param[in] data 输入字符串（需为YYYY-MM-DD格式）
 * @return RC 操作结果：SUCCESS(成功)、SCHEMA_FIELD_TYPE_MISMATCH(格式错误)、INVALID_DATE(日期非法)
 */
RC DateType::set_value_from_str(Value &val, const std::string &data) const {
  // 1. 解析字符串为date类型的值
  int32_t date_days = 0;
  if (!parse_date_str(data, date_days)) {
    LOG_WARN("Failed to parse date string: %s", data.c_str());
    return RC::SCHEMA_FIELD_TYPE_MISMATCH;
  }

  // 2. 设置Value的类型和值（DATE类型 + date值）
  val.set_type(AttrType::DATES);
  val.set_date(date_days);

  return RC::SUCCESS;
}

/**
 * @brief 将DATE类型Value转换为字符串（YYYY-MM-DD格式）
 * @param[in] val 输入的DATE类型Value
 * @param[out] result 输出的字符串
 * @return RC 操作结果：SUCCESS(成功)、SCHEMA_FIELD_TYPE_MISMATCH(输入非DATE类型)
 */
RC DateType::to_string(const Value &val, std::string &result) const {
  // 1. 校验输入类型（必须为DATE）
  if (val.attr_type() != AttrType::DATES) {
    LOG_WARN("Date to_string failed: val is not DATE (type=%d)", val.attr_type());
    result.clear();
    return RC::SCHEMA_FIELD_TYPE_MISMATCH;
  }

  // 2. 获取日期天数并格式化为字符串
  int32_t date_days = val.get_date_days();
  if (!format_date_days(date_days, result)) {
    LOG_WARN("Failed to format date days: %d", date_days);
    result.clear();
    return RC::INVALID_DATE;
  }

  return RC::SUCCESS;
}